//
// Created by A on 2024/6/23.
//

#include "mLink.h"
#include "malloc.h"

//初始化一个链表（建立头节点）
LNode* List_init(void) {
    LNode* p;
    p = (LNode*)malloc(sizeof(LNode));
    if (!p) return NULL;//内存不足分配失败
    else {
        p->next = NULL;
        return p;
    }
}


//判断一个单链表是否为空表
int ListEmpty(LNode* L) {
    if (L->next == NULL)
        return 1;//表示为空
    else
        return 0;
}
//头节点也释放
//销毁单链表
int DestoryList_L(LNode* L) {
    LNode* p;//或者LinkList p
    while (L) {//L!=NULL
        p = L;//先将L指向的结点给P
        L = L->next;//然后L指向下一个节点
        free(p);//删除刚刚的节点
    }//循环直到L指向空（NULL）
    return 1;
}
//只释放后面的
//清空一个单链表
int ClearList(LNode* L) {
    LNode* p, * q;//定义两个中间变量指针
    p = L->next;//指向第一个节点   p=L为首元节点
    q = p;//这一步是为了避免报错，先将q给一个初值
    while (p != NULL) {//或者条件为p也行
        q = q->next;//q提前指向下一个
        free(p);//释放p
        p = q;//此时如果指向的下一个为空则结束循环，不为空则继续
    }
    L->next = NULL;//第一个节点已经被释放，将头节点的next设置为空
    return 1;
}

//获取某个节点的数据区，通过data接收
int GetElem_L(LNode* L, int i, data* data) {
    LNode* p;//中间指针变量
    int j = 0;//用于记录找到第几个节点了
    p = L->next;//首先指向第一个节点,即这里不算首元节点，将我们定义的第一个当作第一个节点
    j = 1;
    while (p && j < i) {//一直往下找，直到这俩条件有一个不成立，即 p为空或者 i==j
        /*题外话，这里开始我将j<i写成i<j了，可让我好找这个该死的bug*/
        p = p->next;
        j++;
    }
    if (!p || j > i)//这里已经退出循环，这俩条件有一个成立就代表没找到，出错了，即 p为空或者 j>i(i=-1,0等不合法数值)
        return 0;
    *data = p->Ldata;//返回当前节点的数据区，由data接收
    return 1;
}

//返回链表的长度.i=0,则不算头节点，i=1，则算头节点
int ListLength(LNode* L) {
    LNode* p;
    int i = 0;
    p = L->next;
    while (p) {
        p = p->next;
        i++;
    }
    return i;
}
//在单链表中按照数据域中的某个值来查找响应节点，返回对应节点的地址
LNode* LocateElem_L_P(LNode* L, int nam) {
    //这里举例查找data中name的值
    LNode* p;
    p = L->next;
    while (p && p->Ldata.key != nam) {
        p = p->next;
    }
    return p;//这一步如果找到了刚好返回的是对应节点的地址，如果没找到刚好是NULL
}

//在单链表中按照第几个节点来查找响应节点，返回对应节点的地址
LNode* LocateElem_LN_P(LNode* L, int n) {
    LNode* p;
    p = L->next;//指向第一个节点
    int i = 1;
    while (p && i < n) {
        p = p->next;
        i++;
    }
    return p;//这一步如果找到了刚好返回的是对应节点的地址，如果没找到刚好是NULL
}


//在单链表中按照数据域中的某个值来查找响应节点，返回对应节点的序号
int LocateElem_L_N(LNode* L, int nam) {
    //这里举例查找data中name的值
    LNode* p;
    p = L->next;
    int j = 1;
    while (p && p->Ldata.key != nam) {
        p = p->next;
        j++;
    }
    if (p) return j;//如果p不为空则是找到了，返回对应的序号
    else  return 0;//反之返回0，表示没找到
}
/**
  * @brief 在第i个节点之前插入一个新节点
  *       （注意引用&是c++中的语法，在C语言中要以指针替换）
  * @param  i: 表示第几个节点
  * @param  dat: 用dat来存储增加节点数据域的数据
  * @retval 0 错误 1成功
  */
int ListInsert_L(LNode* L, int i, data dat)//，数据域用传入的dat
{
    LNode* p;
    int j = 0;
    p = L;//p指向首元节点
    while (p && j < i - 1) {
        p = p->next;
        j++;
    }
    if (!p || j > i - 1) return 0;
    LNode* s;
    s = (LNode*)malloc(sizeof(LNode));
    if (s == NULL) return 0;
    s->Ldata = dat;
    s->next = p->next;//将新建的节点指向后面的节点，把原来i位置的后面的地址赋值
    p->next = s;//将原来i位置的节点指向新建的节点
    return 1;
}
/**
  * @brief 将链表中第i个元素删除
  *       （注意引用&是c++中的语法，在C语言中要以指针替换）
  * @param  i: 表示删除第几个元素
  * @param  dat: 用dat来存储被删除数据的数据域
  * @retval 0 错误 1成功
  */
int ListDelete_L(LNode* L, int i, data* dat) {//将链表中第i个元素删除，用dat来存储被删除数据的数据域
    LNode* p, * q; int j = 0;
    p = L;
    while (p->next && j < i - 1) {
        p = p->next;
        j++;
    }
    if (!(p->next) || j > i - 1) return 0;
    q = p->next;//保存被删除节点的地址
    p->next = q->next;//将前驱节点指向后面的节点
    *dat = q->Ldata;//保存被删除节点的数据域
    free(q);//释放内存
    return 1;
}

/**
  * @brief 用头插法来建立一个链表,这里我做了一些修改
  *        原版是在函数内部给 L分配空间，这里我并没有这样做
  *        因此在使用该函数之前必须要调用List_init（）来为L分配空间
  *       （注意引用&是c++中的语法，在C语言中要以指针替换）
  * @param  L: LNode*  pp 定义的一个指针，指向头节点
  * @param  dat: data 类型的数据域结构体，用于给新建节点的数据域赋值
  * @retval 0 错误 1成功
  */
int CreateList_H(LNode* L, data dat) {
    if (L == NULL)//检查L是否为空
        return 0;//表示传入的L并没有分配空间
    LNode* p;
    p = (LNode*)malloc(sizeof(LNode));//创建一个新节点
    if (p == NULL) return 0;
    p->Ldata = dat;//将数据放入数据域
    p->next = L->next;//将头节点之后的元素放到新建节点后
    L->next = p;//将新节点放入头节点后
    return 1;
}
/**
  * @brief 用尾插法来建立一个链表,
  *        原版是在函数内部给 L分配空间，这里我并没有这样做
  *        因此在使用该函数之前必须要调用List_init（）来为L分配空间
  *       （注意引用&是c++中的语法，在C语言中要以指针替换）
  * @param  L: LNode*  pp 定义的一个指针，指向头节点
  * @param  dat: data 类型的数据域结构体，用于给新建节点的数据域赋值
  * @retval 0 错误 1成功
  */
int CreateList_R(LNode* L, data dat) {
    if (L == NULL)//检查L是否为空
        return 0;//表示传入的L并没有分配空间
    LNode* p;//新建的节点
    LNode* q; //用来寻找最后一个节点
    q = L;
    p = (LNode*)malloc(sizeof(LNode));//创建一个新节点
    if (p == NULL) return 0;//创建新节点失败
    p->Ldata = dat;//将数据放入数据域
    p->next = NULL;//将新建节点的后继指针置空
    while (q->next) {//找到最后一个节点
        q = q->next;
    }
    q->next = p;//将新建的节点接在后面
    return 1;
}

